package com.northpool.operator.common.number;

import cn.hutool.core.compiler.CompilerUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.northpool.operator.annotation.InputParam;
import com.northpool.operator.annotation.InputParams;
import com.northpool.operator.annotation.OperatorInfo;
import com.northpool.operator.annotation.OutputParam;
import com.northpool.operator.annotation.OutputParams;
import com.northpool.operator.common.algorithm.OperatorTestBuild;
import com.northpool.operator.common.algorithm.TestParamBuilder;
import com.northpool.operator.param.ParamTool;
import com.northpool.operator.type.TypeEnum;
import com.northpool.operator.utils.StpOperatorHelper;

import java.lang.reflect.Method;

@OperatorInfo(ref = "NumberOperator", name = "数字工具", description = "Java语言处理数字工具")
@OutputParams({
        @OutputParam(ref = "result", name = "处理过后的数字", desc = "处理过后的数字", type = TypeEnum.NUMBER)
})
public class NumberOperator extends StpOperatorHelper {

    @InputParams({
            @InputParam(ref = "expression", name = "数字处理表达式", desc = "数字处理表达式，仅支持Java语法，不能以括号开头。如：'2+6/3+1.2'")
    })
    public NumberOperator() {
    }

    public static void main(String[] args) throws Exception {
        OperatorTestBuild.execute(NumberOperator.class,
                TestParamBuilder.aBuilder()
                        .param("expression", "2+6/3+1.2")
                        .build());
    }

    @Override
    public void execute(ParamTool paramTool) throws Exception {
        String expression = paramTool.getStr("expression");
        if (StrUtil.isBlank(expression)) {
            System.out.println("error: 表达式不能为空");
            this.failedExit();
        }
        String result = this.formatString(expression);
        this.result("result", result);
    }

    public String formatString(String expression) throws ClassNotFoundException {
        String javaCode =
                "public class NumberJava {\n" +
                        "public Object run() {\n" +
                        "   return " + expression + ";\n" +
                        "}\n" +
                        "}";
        ClassLoader compile = compile(javaCode);
        final Class<?> cla = compile.loadClass("NumberJava");
        Object result = exec(cla);
        if (NumberUtil.isNumber(StrUtil.utf8Str(result))) {
            return StrUtil.utf8Str(result);
        } else{
            throw new RuntimeException("表达式返回值不是数值");
        }
    }

    public ClassLoader compile(String javaCode) {
        return CompilerUtil.getCompiler(null)
                // 被编译的源码字符串
                .addSource("NumberJava", javaCode)
                .compile();
    }

    public Object exec(Class<?> cla) {
        try {
            Object o = cla.getDeclaredConstructor().newInstance();
            Method method = cla.getMethod("run");
            return (Object) method.invoke(o);
        } catch (Exception e) {
            System.out.println("error: 表达式执行失败");
            this.error(ExceptionUtil.getMessage(e));
            System.exit(1);
        }
        return null;
    }
}
